package com.richard.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;




//懒汉式单例
public class LazyMan {

    private static boolean qinjiang = false;

    private  LazyMan(){

        synchronized (LazyMan.class){
            if (qinjiang == false){
                qinjiang = true;
            }else {
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
//            if (lazyMan != null){
//                throw new RuntimeException("不要试图使用反射破坏异常");
//            }
        }
//        System.out.println(Thread.currentThread().getName() + "ok");
    }

    private volatile static LazyMan lazyMan;


    public static LazyMan getLazyMan(){

        //加锁   双重检测锁模式的  懒汉式单例  DCL懒汉式
        if (lazyMan == null){
            synchronized (LazyMan.class){
                if (lazyMan == null){
                    lazyMan = new LazyMan();   //不是一个原子性操作
                    /**
                     * 会经过三步操作
                     * 1.分配内存空间
                     * 2.执行构造方法，初始化对象
                     * 3.把这个对象指向这个空间
                     *
                     * 以上的步骤，默认情况是 123
                     * 但是，如果出现 132 的情况，恰巧此时A线程占有了，如果此时B线程也要使用的话，
                     * 就会直接认为lazyMan不为空，则会返回lazyMan，然而此时lazyMan还没有完成创建，
                     * 此时是一片虚无，会导致错误。所以需要在lazyMan前面加  volatile  。
                     */
                }
            }
        }
        return lazyMan;
    }

    //单线程下确实单例OK，但是多线程并发中会出现问题


    //反射
    public static void main(String[] args) throws Exception {
//        LazyMan instance = LazyMan.getLazyMan();

        Field qinjiang = LazyMan.class.getDeclaredField("qinjiang");
        qinjiang.setAccessible(true);


        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);

        declaredConstructor.setAccessible(true);
        LazyMan instance = declaredConstructor.newInstance();

        qinjiang.set(instance,false);

        LazyMan instance2 = declaredConstructor.newInstance();

        System.out.println(instance);
        System.out.println(instance2);
    }
/**
    public static void main(String[] args){
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                LazyMan.getLazyMan();
            }).start();


        }
    }
 */
}
